#include "fs.h"
#include "super_block.h"
#include "inode.h"
#include "dir.h"
#include "stdint.h"
#include "stdio-kernel.h"
#include "list.h"
#include "string.h"
#include "ide.h"
#include "global.h"
#include "debug.h"
#include "memory.h"
#include "file.h"

struct partition* cur_part; // 默认情况下操作的是哪个分区

// 在分区链表中找到名为 part_name 的分区，并将其指针赋值给 cur_part
static bool mount_partition(struct list_elem* pelem, int arg) {
    char* part_name = (char*) arg;
    struct partition* part = elem2entry(struct partition, part_tag, pelem);

    if(!strcmp(part -> name, part_name)) {
        cur_part = part;
        struct disk* hd = cur_part -> my_disk;

        // 准备 super_block 结构体准备用来存储从硬盘读入的超级块数据
        struct super_block* sb_buf = (struct super_block*) sys_malloc(SECTOR_SIZE);

        // 在内存中创建分区 cur_part 的超级块
        cur_part -> sb = (struct super_block*) sys_malloc(sizeof(struct super_block));

        if(cur_part -> sb == NULL)
            PANIC("alloc memory failed!");
        
        // 读入超级块
        memset(sb_buf, 0, SECTOR_SIZE);
        ide_read(hd, cur_part -> start_lba + 1, sb_buf, 1);

        // 把 sb_buf 中的超级块信息复制到分区的超级块 sb 中
        memcpy(cur_part -> sb, sb_buf, sizeof(struct super_block));

        /*---------------------------------------*/
        // 将硬盘上的块位图读入到内存
        /*---------------------------------------*/
        cur_part -> block_bitmap.bits = (uint8_t*) sys_malloc(sb_buf -> block_bitmap_sects * SECTOR_SIZE);
        if(cur_part -> block_bitmap.bits == NULL)
            PANIC("alloc memory failed!");
        cur_part -> block_bitmap.btmp_bytes_len = sb_buf -> block_bitmap_sects * SECTOR_SIZE;
        // 从硬盘上读入块位图到分区的 block_bitmap.bits
        ide_read(hd, sb_buf -> block_bitmap_lba, cur_part -> block_bitmap.bits, sb_buf -> block_bitmap_sects);

        /*---------------------------------------*/
        // 将硬盘上的 inode 位图读入到内存
        /*---------------------------------------*/
        cur_part -> inode_bitmap.bits = (uint8_t*) sys_malloc(sb_buf -> inode_bitmap_sects * SECTOR_SIZE);
        if(cur_part -> inode_bitmap.bits == NULL)
            PANIC("alloc memroy failed!");
        cur_part -> inode_bitmap.btmp_bytes_len = sb_buf -> inode_bitmap_sects * SECTOR_SIZE;
        // 从硬盘上读入 inode 位图到分区的 inode_bitmap.bits
        ide_read(hd, sb_buf -> inode_bitmap_lba, cur_part -> inode_bitmap.bits, sb_buf -> inode_bitmap_sects);

        // ------------
        list_init(&cur_part -> open_inodes);
        printk("mount %s done!\n", part -> name);

     /* 此处返回true是为了迎合主调函数list_traversal的实现,与函数本身功能无关。
        只有返回true时list_traversal才会停止遍历,减少了后面元素无意义的遍历.*/
        return true;
    }
    return false; // 使 list_traversal 继续遍历
}

// 格式化分区，也就是初始化分区中的元信息，从而创建文件系统
static void partition_format(struct partition* part) {
    // 为了方便，一个块大小 = 一个扇区
    uint32_t boot_sector_sects = 1;
    uint32_t super_block_sects = 1;
    // inode 位图所占用的扇区数，最多支持 4096 个文件
    // 目前我理解为：512byte = 4096bit, 即每个 bit 对应一个“块”, 每个块可以是 inode
    uint32_t inode_bitmap_sects = DIV_ROUND_UP(MAX_FILES_PER_PART, BITS_PER_SECTOR);
    // inode_table 所需要的扇区数
    uint32_t inode_table_sects = DIV_ROUND_UP(((sizeof(struct inode) * MAX_FILES_PER_PART)), SECTOR_SIZE);
    // 已使用的扇区数
    uint32_t used_sects = boot_sector_sects + super_block_sects + inode_bitmap_sects + inode_table_sects;
    // 空闲空间的扇区数
    uint32_t free_sects = part -> sec_cnt - used_sects;

    // 块的位图 所占用的扇区数
    // 一个块 = 一个扇区, 4096 位 = 4096 个块, 直接除于 4096 可得到扇区数
    uint32_t block_bitmap_sects;
    block_bitmap_sects = DIV_ROUND_UP(free_sects, BITS_PER_SECTOR);
    // 位图中位的个数
    uint32_t block_bitmap_bit_len = free_sects - block_bitmap_sects;
    block_bitmap_sects = DIV_ROUND_UP(block_bitmap_bit_len, BITS_PER_SECTOR);

    /*------------------------------------*/
    // super_block 超级块的初始化
    /*------------------------------------*/
    struct super_block sb;
    sb.magic = 0x19590318;
    sb.sec_cnt = part -> sec_cnt;
    sb.inode_cnt = MAX_FILES_PER_PART;
    sb.part_lba_base = part -> start_lba;

    sb.block_bitmap_lba = sb.part_lba_base + 2; // 第 0 块是引导块，第 1 块是超级块
    sb.block_bitmap_sects = block_bitmap_sects;

    sb.inode_bitmap_lba = sb.block_bitmap_lba + sb.block_bitmap_sects;
    sb.inode_bitmap_sects = inode_bitmap_sects;

    sb.inode_table_lba = sb.inode_bitmap_lba + sb.inode_bitmap_sects;
    sb.inode_table_sects = inode_table_sects;

    sb.data_start_lba = sb.inode_table_lba + sb.inode_table_sects;
    sb.root_inode_no = 0;
    sb.dir_entry_size = sizeof(struct dir_entry);

    printk("%s info:\n", part->name);
    printk("   magic:0x%x\n   part_lba_base:0x%x\n   all_sectors:0x%x\n   inode_cnt:0x%x\n   block_bitmap_lba:0x%x\n   block_bitmap_sectors:0x%x\n   inode_bitmap_lba:0x%x\n   inode_bitmap_sectors:0x%x\n   inode_table_lba:0x%x\n   inode_table_sectors:0x%x\n   data_start_lba:0x%x\n", sb.magic, sb.part_lba_base, sb.sec_cnt, sb.inode_cnt, sb.block_bitmap_lba, sb.block_bitmap_sects, sb.inode_bitmap_lba, sb.inode_bitmap_sects, sb.inode_table_lba, sb.inode_table_sects, sb.data_start_lba);

    /*-----------------------------------------*/
    // 将超级块写入本分区的 1 扇区（0 扇区是引导扇区）
    /*-----------------------------------------*/
    struct disk* hd = part -> my_disk;
    ide_write(hd, part -> start_lba + 1, &sb, 1);

    printk("   super_block_lba:0x%x\n", part->start_lba + 1);

    // 找出数据量最大的元信息，将其作为存储缓冲区
    uint32_t buf_size = (sb.block_bitmap_sects >= sb.inode_bitmap_sects ? sb.block_bitmap_sects : sb.inode_bitmap_sects);
    buf_size = (buf_size >= sb.inode_table_sects ? buf_size : sb.inode_table_sects) * SECTOR_SIZE;
    uint8_t* buf = (uint8_t*) sys_malloc(buf_size);

    /*-----------------------------------------*/
    // 将块位图初始化并写入 sb.block_bitmap_lba
    /*-----------------------------------------*/
    buf[0] |= 0x01; // 第 0 块先预留给根目录，位图先占位
    uint32_t block_bitmap_last_byte = block_bitmap_bit_len / 8; // 位图的长度，以字节为单位
    uint8_t block_bitmap_last_bit = block_bitmap_bit_len % 8; // 最后不足一个字节的位的个数
    // last_size 是位图所在扇区最后不足一扇区的部分
    uint32_t last_size = SECTOR_SIZE - (block_bitmap_last_byte % SECTOR_SIZE);

    // 将位图最后一个字节所在扇区的有效位全部置为 1, 也就是说超出的那 last_size 全部设置为已占用状态
    memset(&buf[block_bitmap_last_byte], 0xFF, last_size);

    // 将最后一个字节中其有效的部分将其置为 0，也就是没有超出的那部分
    uint8_t bit_idx = 0;
    while(bit_idx <= block_bitmap_last_bit)
        buf[block_bitmap_last_byte] &= ~(1 << bit_idx++);
    ide_write(hd, sb.block_bitmap_lba, buf, sb.block_bitmap_sects);

    /*--------------------------------------------*/
    // 将 inode 位图初始化并写入 sb.inode_bitmap_lba
    /*--------------------------------------------*/
    // 先清空缓冲区
    memset(buf, 0, buf_size);
    buf[0] |= 0x01; // 第 0 个 inode 分给了根目录
    /**
     * 因为 inode_table 共 4096 个 inode，inode_bitmap 位图正好占用一个扇区
     * 即 inode_bitmap_sects = 1
     * 所以位图中的所有扇区均是有效位，无需再像 block_bimap 那样处理残余的扇区
     */
    ide_write(hd, sb.inode_bitmap_lba, buf, sb.inode_bitmap_sects);

    /*--------------------------------------------*/
    // 将 inode 数组初始化并写入 sb.inode_table_lba
    /*--------------------------------------------*/
    memset(buf, 0, buf_size);
    // 初始化第一个 inode 项，它表示根目录
    struct inode* i = (struct inode*) buf; 
    i -> i_size = sb.dir_entry_size * 2; // . 和 ..
    i -> i_no = 0; // inode 编号
    i -> i_sectors[0] = sb.data_start_lba; // 第 0 个块指向 sb.data_start_lba
                                           // 也就是将根目录安排在最开始的空闲块中
    ide_write(hd, sb.inode_table_lba, buf, sb.inode_table_sects);

    /*--------------------------------------------*/
    // 将根目录初始化并写入 sb.data_start_lba
    /*--------------------------------------------*/
    // 写入目录项 . 和 ..
    memset(buf, 0, buf_size);
    struct dir_entry* p_de = (struct dir_entry*) buf;
    // 初始化当前目录 .
    memcpy(p_de -> filename, ".", 1);
    p_de -> i_no = 0;
    p_de -> f_type = FT_DIRECTORY;
    p_de++;

    // 初始化当前目录的父目录 ..
    memcpy(p_de -> filename, "..", 2);
    p_de -> i_no = 0; // 根父目录还是自己
    p_de -> f_type = FT_DIRECTORY;

    ide_write(hd, sb.data_start_lba, buf, 1);

    printk("   root_dir_lba:0x%x\n", sb.data_start_lba);
    printk("%s format done\n", part->name);
    sys_free(buf);
}

// 将最顶层的路径名称解析出来
static char* path_parse(char* pathname, char* name_store) {
    if(pathname[0] == '/') { // 根目录不单独解析
        /* 路径中出现1个或多个连续的字符'/',将这些'/'跳过,如"///a/b" */
        while(*(++pathname) == '/');
    }

    // 一般路径解析
    while(*pathname != '/' && *pathname != 0)
        *name_store++ = *pathname++;
    
    if(pathname[0] == 0)
        return NULL;
    
    return pathname;
}

// 返回路径深度
int32_t path_depth_cnt(char* pathname) {
    ASSERT(pathname != NULL);
    char* p = pathname;
    char name[MAX_FILE_NAME_LEN];
    uint32_t depth = 0;

    // 解析路径，从中拆分出各级名称
    p = path_parse(p, name);
    while(name[0]) {
        depth++;
        memset(name, 0, MAX_FILE_NAME_LEN);
        if(p) // 若 p != NULL，则继续解析
            p = path_parse(p, name);
    }

    return depth;
}

// 搜索文件
static int search_file(const char* pathname, struct path_search_record* searched_record) {
    // 若待查找的是根目录，直接返回
    if (!strcmp(pathname, "/") || !strcmp(pathname, "/.") || !strcmp(pathname, "/..")) {
        searched_record->parent_dir = &root_dir;
        searched_record->file_type = FT_DIRECTORY;
        searched_record->searched_path[0] = 0;	   // 搜索路径置空
        return 0;
    }

    uint32_t path_len = strlen(pathname);
    /* 保证pathname至少是这样的路径/x且小于最大长度 */
    ASSERT(pathname[0] == '/' && path_len > 1 && path_len < MAX_PATH_LEN);
    char* sub_path = (char*) pathname;
    struct dir* parent_dir = &root_dir;
    struct dir_entry dir_e;

    char name[MAX_FILE_NAME_LEN] = {0};

    searched_record -> parent_dir = parent_dir;
    searched_record -> file_type = FT_UNKNOWN;
    uint32_t parent_inode_no = 0; // 父目录的 inode 编号

    sub_path = path_parse(sub_path, name);
    while(name[0]) { // 路径不许为空
        /* 记录查找过的路径,但不能超过searched_path的长度512字节 */
        ASSERT(strlen(searched_record->searched_path) < 512);

        // 记录已存在的父目录
        strcat(searched_record -> searched_path, "/");
        strcat(searched_record -> searched_path, name);

        if(search_dir_entry(cur_part, parent_dir, name, &dir_e)) { // 在所给的目录中查找文件
            memset(name, 0, MAX_FILE_NAME_LEN);
            if(sub_path) // 继续解析路径
                sub_path = path_parse(sub_path, name);
            if(FT_DIRECTORY == dir_e.f_type) { // 被打开的是目录
                parent_inode_no = parent_dir -> inode -> i_no;
                dir_close(parent_dir);
                parent_dir = dir_open(cur_part, dir_e.i_no); // 更新父目录
                searched_record -> parent_dir = parent_dir;
                continue;
            } else if(FT_REGULAR == dir_e.f_type) { // 被打开的是普通文件
                searched_record -> file_type = FT_REGULAR;
                return dir_e.i_no;
            }
        } else { // 找不到
            /**
             * 找不到目录项时，要留着 parent_dir 不要关闭
             * 因为若需要创建文件的话，需要在 parent_dir 中创建
             */
            return -1;
        }
    }

    // ------------------------------------------
    // 执行到这里，可说明：
    // 1. 路径 pathname 已经被完整的解析过了，各级都存在
    // 2. pathname 的最后一层路径不是普通文件，而是目录
    // ------------------------------------------
    dir_close(searched_record -> parent_dir);

    searched_record -> parent_dir = dir_open(cur_part, parent_inode_no);
    searched_record -> file_type = FT_DIRECTORY;
    return dir_e.i_no;
}

// 打开或创建文件成功后，返回文件描述符
int32_t sys_open(const char* pathname, uint8_t flags) {
    if(pathname[strlen(pathname)] == '/') {
        printk("can`t open a directory %s\n",pathname);
        return -1;
    }

    ASSERT(flags <= 7);

    int32_t fd = -1; // 默认找不到

    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));

    // 记录目录深度，便于判断中间某个目录不存在的情况
    uint32_t pathname_depth = path_depth_cnt((char*) pathname);

    // 先检查文件是否存在
    int inode_no = search_file(pathname, &searched_record);
    bool found = inode_no != -1 ? true : false;

    if(searched_record.file_type == FT_DIRECTORY) {
        printk("can`t open a direcotry with open(), use opendir() to instead\n");
        dir_close(searched_record.parent_dir);
        return -1;
    }

    uint32_t path_search_depth = path_depth_cnt(searched_record.searched_path);

    // 判断是否把 pathname 各层目录都访问到了，即是否出现目录/文件找不到的情况
    if(pathname_depth != path_search_depth) {
        printk("cannot access %s: Not a directory, subpath %s is`t exist\n", \
	     pathname, searched_record.searched_path);
        dir_close(searched_record.parent_dir);
        return -1;
    }

    if(!found && !(flags & O_CREAT)) { // 找不到目标文件，且并不是要创建文件
        printk("in path %s, file %s is`t exist\n", \
	     searched_record.searched_path, \
	     (strrchr(searched_record.searched_path, '/') + 1));
        dir_close(searched_record.parent_dir);
        return -1;
    } else if(found && (flags & O_CREAT)) { // 找到目标文件，且是创建文件操作，表示：创建的文件已存在
        printk("%s has already exist!\n", pathname);
        dir_close(searched_record.parent_dir);
        return -1;
    }

    switch(flags & O_CREAT) {
        case O_CREAT:
            printk("creating file.\n");
            fd = file_create(searched_record.parent_dir, (strrchr(pathname, '/') + 1), flags);
            dir_close(searched_record.parent_dir);
            break;
        // 其余为打开文件
        default: // O_RDONLY, O_WRONLY, O_RDWR
            fd = file_open(inode_no, flags);
    }

    return fd; // 此 fd 并非全局文件表 file_table 的下标，而是进程 PCB -> fd_table 的下标
}

// 将文件描述符转换为文件表下标
static uint32_t fd_local2global(uint32_t local_fd) {
    struct task_struct* cur = running_thread();
    int32_t global_fd = cur -> fd_table[local_fd];
    ASSERT(global_fd >= 0 && global_fd < MAX_FILE_OPEN);
    return (uint32_t) global_fd;
}

// 关闭文件描述符 fd 所指向的文件，成功返回0，失败返回-1
int32_t sys_close(int32_t fd) {
    int32_t ret = -1;
    if(fd > 2) { // 跨越标准输入输出
        uint32_t _fd = fd_local2global(fd);
        ret = file_close(&file_table[_fd]);
        running_thread() -> fd_table[fd] = -1; // 将文件描述符重置为可用状态
    }
    return ret;
}

// 将 buf 中连续 count 个字节写入文件描述符 fd，成功返回字节数，失败返回-1
int32_t sys_write(int32_t fd, const void* buf, uint32_t count) {
    if(fd < 0) {
        printk("sys_write: fd error.\n");
        return -1;
    }
    if(fd == stdout_no) {
        char tmp_buf[1024] = {0};
        memcpy(tmp_buf, buf, count);
        console_put_str(tmp_buf);
        return count;
    }
    uint32_t _fd = fd_local2global(fd);
    struct file* wr_file = &file_table[_fd];
    if(wr_file -> fd_flag & O_WRONLY || wr_file -> fd_flag & O_RDWR) {
        uint32_t bytes_written = file_write(wr_file, buf, count);
        return bytes_written;
    } else {
        console_put_str("sys_write: not allowed to write file without flag O_RDWR or O_WRONLY.\n");
        return -1;
    }
}

// 从文件描述符 fd 指向的文件中读取 count 个字节到 buf，成功返回读取的字节数，到文末返回-1
int32_t sys_read(int32_t fd, void* buf, uint32_t count) {
    if(fd < 0) {
        printk("sys_read: fd error\n");
        return -1;
    }
    ASSERT(buf != NULL);
    uint32_t _fd = fd_local2global(fd);
    return file_read(&file_table[_fd], buf, count);
}

// 重置文件偏移指针，返回新的偏移量
int32_t sys_lseek(int32_t fd, int32_t offset, uint8_t whence) {
    if(fd < 0) {
        printk("sys_lseek: fd error\n");
        return -1;
    }
    ASSERT(whence > 0 && whence < 4);
    uint32_t _fd = fd_local2global(fd);
    struct file* pf = &file_table[_fd];
    int32_t new_pos = 0;
    int32_t file_size = (int32_t) pf -> fd_inode -> i_size;
    switch(whence) {
        case SEEK_SET: // 相对于文件开头偏移 offset
            new_pos = offset;
            break;
        case SEEK_CUR: // 相对于当前位置 fd_pos 偏移 offset
            new_pos = (int32_t) pf -> fd_pos + offset;
            break;
        case SEEK_END: // 相对于文件结尾偏移 offset
            new_pos = file_size + offset;
            break;
    }
    if(new_pos < 0 || new_pos > (file_size - 1)) return -1;
    pf -> fd_pos = new_pos;
    return pf -> fd_pos;
}

// 删除文件（非目录），成功返回0，失败返回-1
int32_t sys_unlink(const char* pathname) {
    ASSERT(strlen(pathname) < MAX_PATH_LEN);

    // 检查待删除的文件是否存在
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = search_file(pathname, &searched_record);

    ASSERT(inode_no != 0);

    if(inode_no == -1) {
        printk("file %s not found!\n", pathname);
        dir_close(searched_record.parent_dir);
        return -1;
    }

    // 判断待删除的目标是否为目录
    if(searched_record.file_type == FT_DIRECTORY) {
        printk("can`t delete a direcotry with unlink(), use rmdir() to instead\n");
        dir_close(searched_record.parent_dir);
        return -1;
    }

    // 检查是否被打开
    // Tips：正在使用的文件不可删除
    uint32_t file_idx = 0;
    while(file_idx < MAX_FILE_OPEN) {
        if(file_table[file_idx].fd_inode != NULL && (uint32_t) inode_no == file_table[file_idx].fd_inode->i_no) {
            break;
        }
        file_idx++;
    }

    if(file_idx < MAX_FILE_OPEN) {
        dir_close(searched_record.parent_dir);
        printk("file %s is in use, not allow to delete!\n", pathname);
        return -1;
    }

    ASSERT(file_idx == MAX_FILE_OPEN);

    void* io_buf = sys_malloc(SECTOR_SIZE + SECTOR_SIZE);
    if(io_buf == NULL) {
        dir_close(searched_record.parent_dir);
        printk("sys_unlink: malloc for io_buf failed\n");
        return -1;
    }

    struct dir* parent_dir = searched_record.parent_dir;
    delete_dir_entry(cur_part, parent_dir, inode_no, io_buf);
    inode_release(cur_part, inode_no);
    sys_free(io_buf);
    dir_close(searched_record.parent_dir);

    return 0;
}

// 创建目录 pathname，成功返回0，失败返回-1
int32_t sys_mkdir(const char* pathname) {
    uint8_t rollback_step = 0;
    void* io_buf = sys_malloc(SECTOR_SIZE * 2);
    if(io_buf == NULL) {
        printk("sys_mkdir: sys_malloc for io_buf failed\n");
        return -1;
    }

    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));

    int inode_no = -1;
    inode_no = search_file(pathname,  &searched_record);
    if(inode_no != -1) { // 文件或目录已存在
        printk("sys_mkdir: file or directory %s exist!\n", pathname);
        rollback_step = 1;
        goto rollback;
    } else { // 中间目录是否缺失
        uint32_t pathname_depth = path_depth_cnt((char*) pathname);
        uint32_t path_searched_depth = path_depth_cnt(searched_record.searched_path);
        // 判断中间目录是否缺失
        if(pathname_depth != path_searched_depth) {
            printk("sys_mkdir: can`t access %s, subpath %s is`t exist\n", pathname, searched_record.searched_path);
            rollback_step = 1;
            goto rollback;
        }
    }

    struct dir* parent_dir = searched_record.parent_dir;
    char* dirname = strrchr(searched_record.searched_path, '/') + 1;

    inode_no = inode_bitmap_alloc(cur_part);
    if(inode_no == -1) {
        printk("sys_mkdir: allocate inode failed\n");
        rollback_step = 1;
        goto rollback;
    }

    struct inode new_dir_inode;
    inode_init(inode_no, &new_dir_inode);

    uint32_t block_bitmap_idx = 0;
    int32_t block_lba = -1;

    // 为目录分配一个块，用来写入目录项 . 和 ..
    block_lba = block_bitmap_alloc(cur_part);
    if(block_lba == -1) {
        printk("sys_mkdir: block_bitmap_alloc for create directory failed\n");
        rollback_step = 2;
        goto rollback;
    }

    new_dir_inode.i_sectors[0] = block_lba;
    block_bitmap_idx = block_lba - cur_part -> sb -> data_start_lba;
    bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);

    // 写入目录项 . 和 ..
    memset(io_buf, 0, SECTOR_SIZE * 2);
    struct dir_entry* p_de = (struct dir_entry*) io_buf;

    // 初始化当前目录 .
    memcpy(p_de -> filename, ".", 1);
    p_de -> i_no = inode_no;
    p_de -> f_type = FT_DIRECTORY;
    p_de++;

    // 初始化目录项 ..
    memcpy(p_de -> filename, "..", 2);
    p_de -> i_no = parent_dir -> inode -> i_no;
    p_de -> f_type = FT_DIRECTORY;

    // 写入目录项
    ide_write(cur_part -> my_disk, new_dir_inode.i_sectors[0], io_buf, 1);

    new_dir_inode.i_size = 2 * cur_part -> sb -> dir_entry_size;

    // 在父目录中添加新的目录项（也就是新创建的那个目录的目录项）
    struct dir_entry new_dir_entry;
    memset(&new_dir_entry, 0, sizeof(struct dir_entry));
    create_dir_entry(dirname, inode_no, FT_DIRECTORY, &new_dir_entry);
    memset(io_buf, 0, SECTOR_SIZE * 2);

    // 父目录将新目录项写入
    if(!sync_dir_entry(parent_dir, &new_dir_entry,  io_buf)) {
        printk("sys_mkdir: sync_dir_entry to disk failed!\n");
        rollback_step = 2;
        goto rollback;
    }

    // 同步父目录 inode
    memset(io_buf, 0, SECTOR_SIZE * 2);
    inode_sync(cur_part, parent_dir -> inode, io_buf);

    // 同步新创建的目录 inode
    memset(io_buf, 0, SECTOR_SIZE * 2);
    inode_sync(cur_part, &new_dir_inode, io_buf);

    // 将位图同步
    bitmap_sync(cur_part, inode_no, INODE_BITMAP);

    sys_free(io_buf);

    dir_close(searched_record.parent_dir);
    return 0;

    rollback:
        switch(rollback_step) {
            case 2:
                bitmap_set(&cur_part -> inode_bitmap, inode_no, 0);
            case 1:
                dir_close(searched_record.parent_dir);
        }
        sys_free(io_buf);
        return -1;
}

// 打开目录，返回目录指针，失败返回NULL
struct dir* sys_opendir(const char* name) {
    ASSERT(strlen(name) < MAX_PATH_LEN);

    // 若是根目录，直接返回
    if(name[0] == '/' && (name[1] == 0 || name[0] == ".")) return &root_dir;

    // 先检查待打开的目录是否存在
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = search_file(name, &searched_record);
    struct dir* ret = NULL;
    if(inode_no == -1) { // 找不到，提示路径不存在
        printk("In %s, sub path %s not exist\n", name, searched_record.searched_path); 
    } else {
        if(searched_record.file_type == FT_REGULAR) { // 目标是文件类型为普通文件，这不合法
            printk("%s is regular file!\n", name);
        } else if(searched_record.file_type == FT_DIRECTORY) { // 找到了目标目录
            ret = dir_open(cur_part, inode_no);
        }
    }

    dir_close(searched_record.parent_dir);

    return ret;
}

// 关闭目录，返回0，失败-1
int32_t sys_closedir(struct dir* dir) {
    int32_t ret = -1;
    if(dir != NULL) {
        dir_close(dir);
        ret = 0;
    }
    return ret;
}

// 读取目录 dir 中的 1 个目录项，返回目录项地址，否则NULL
struct dir_entry* sys_readdir(struct dir* dir) {
    ASSERT(dir != NULL);
    return dir_read(dir);
}

// 把目录 dir 的指针 dir_pos 置为 0
void sys_rewinddir(struct dir* dir) {
    dir -> dir_pos = 0;
}

// 删除空目录，成功0，失败-1
int32_t sys_rmdir(const char* pathname) {
    // 先检查文件是否存在
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = search_file(pathname, &searched_record);
    ASSERT(inode_no != 0);
    int retval = -1;

    if(inode_no == -1) { // 已存在
        printk("In %s, sub path %s not exist\n", pathname, searched_record.searched_path); 
    } else {
        if(searched_record.file_type == FT_REGULAR) { // 是普通文件类型
            printk("%s is regular file!\n", pathname);
        } else {
            struct dir* dir = dir_open(cur_part, inode_no);
            if(!dir_is_empty(dir)) { // 判断目录是否为空
                printk("dir %s is not empty, it is not allowed to delete a nonempty directory!\n", pathname);
            } else { // 空目录，进行删除
                if(!dir_remove(searched_record.parent_dir, dir)) retval = 0;
            }
            dir_close(dir);
        }
    }

    dir_close(searched_record.parent_dir);
    return retval;
}

// 获得父目录的 inode 编号
static uint32_t get_parent_dir_inode_nr(uint32_t child_inode_nr, void* io_buf) {
    struct inode* child_dir_inode = inode_open(cur_part, child_inode_nr);
    uint32_t block_lba = child_dir_inode -> i_sectors[0];
    ASSERT(block_lba >= cur_part -> sb -> data_start_lba);
    inode_close(child_dir_inode);
    ide_read(cur_part -> my_disk, block_lba, io_buf, 1);
    struct dir_entry* dir_e = (struct dir_entry*) io_buf;
    // 第0个目录项是., 第1个目录项是 ..
    ASSERT(dir_e[1].i_no < 4096 && dir_e[1].f_type == FT_DIRECTORY);
    return dir_e[1].i_no;
}

// 在 inode 编号为 p_inode_nr 的目录中查到 inode 编号为 c_inode_nr 的子目录名称，将名字存入 path
static int get_child_dir_name(uint32_t p_inode_nr, uint32_t c_inode_nr, char* path, void* io_buf) {
    struct inode* parent_dir_inode = inode_open(cur_part, p_inode_nr);
    uint8_t block_idx = 0;
    uint32_t all_blocks[140] = {0}, block_cnt = 12;
    while(block_idx < 12) {
        all_blocks[block_idx] = parent_dir_inode -> i_sectors[block_idx];
        block_idx++;
    }
    if(parent_dir_inode -> i_sectors[12]) {
        ide_read(cur_part -> my_disk, parent_dir_inode -> i_sectors[12], all_blocks + 12, 1);
        block_cnt = 140;
    }
    inode_close(parent_dir_inode);

    struct dir_entry* dir_e = (struct dir_entry*) io_buf;
    uint32_t dir_entry_size = cur_part -> sb -> dir_entry_size;
    uint32_t dir_entrys_per_sec = 512 / dir_entry_size;
    block_idx = 0;

    // 遍历所有块
    while(block_idx < block_cnt) {
        if(all_blocks[block_idx] != 0) {
            ide_read(cur_part -> my_disk, all_blocks[block_idx], io_buf, 1);
            uint8_t dir_e_idx = 0;
            // 遍历该扇区的所有目录项
            while(dir_e_idx < dir_entrys_per_sec) {
                if((dir_e + dir_e_idx) -> i_no == c_inode_nr) { // 找到目标
                    strcat(path, "/");
                    strcat(path, (dir_e + dir_e_idx) -> filename);
                    return 0;
                }
                dir_e_idx++;
            }
            block_idx++;
        }
    }

    return -1;
}

// 将当前工作目录绝对路径写入 buf
char* sys_getcwd(char* buf, uint32_t size) {
    ASSERT(buf != NULL);
    void* io_buf = sys_malloc(SECTOR_SIZE);
    if(io_buf == NULL) {
        return NULL;
    }

    struct task_struct* cur_thread = running_thread();
    int32_t parent_inode_nr = 0;
    int32_t child_inode_nr = cur_thread -> cwd_inode_nr;
    ASSERT(child_inode_nr >= 0 && child_inode_nr < 4096);
    if(child_inode_nr == 0) {
        buf[0] = '/';
        buf[1] = 0;
        return buf;
    }

    memset(buf, 0, size);
    char full_path_reverse[MAX_PATH_LEN] = {0};

    // 从下往上查找父目录，直到找到根目录为止
    while(child_inode_nr) {
        parent_inode_nr = get_parent_dir_inode_nr(child_inode_nr, io_buf);
        if(get_child_dir_name(parent_inode_nr, child_inode_nr, full_path_reverse, io_buf) == -1) {
            // 未找到对应的名字
            sys_free(io_buf);;
            return NULL;
        }
        child_inode_nr = parent_inode_nr;
    }

    ASSERT(strlen(full_path_reverse) <= size);
    /**
     * 至此 full_path_reverse 中的路径是反着的
     * 即子目录在左边，父目录在右边
     * 现在将其逆转
    */
   char* last_slash; // 
   while((last_slash = strrchr(full_path_reverse, '/'))) {
        uint16_t len = strlen(buf);
        strcpy(buf + len, last_slash);
        *last_slash = 0;
   }

   sys_free(io_buf);
   return buf;
}

// 更改当前工作目录为绝对路径 path，成功0，失败-1
int32_t sys_chdir(const char* path) {
    int32_t ret = -1;
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = search_file(path, &searched_record);
    if(inode_no != -1) {
        if(searched_record.file_type == FT_DIRECTORY) {
            running_thread() -> cwd_inode_nr = inode_no;
            ret = 0;
        } else {
            printk("sys_chdir: %s is regular file or other!\n", path);
        }
    }
    dir_close(searched_record.parent_dir);
    return ret;
}

// 获取文件属性信息，存入到 buf 中，成功0，失败-1
int32_t sys_stat(const char* path, struct stat* buf) {
    // 找的是根目录
    if(!strcmp(path, "/") || !strcmp(path, "/.") || !strcmp(path, "/..")) {
        buf -> st_filetype = FT_DIRECTORY;
        buf -> st_ino = 0;
        buf -> st_size = root_dir.inode -> i_size;
        return 0;
    }

    int ret = -1;
    struct path_search_record searched_record;
    memset(&searched_record, 0, sizeof(struct path_search_record));
    int inode_no = search_file(path, &searched_record);
    if(inode_no != -1) { // 找到了
        struct inode* obj_inode = inode_open(cur_part, inode_no);
        buf -> st_filetype = searched_record.file_type;
        buf -> st_ino = inode_no;
        buf -> st_size = obj_inode -> i_size;
        ret = 0;
        inode_close(obj_inode);
    } else { // 未找到
        printk("sys_stat: %s not found.\n", path);
    }
    dir_close(searched_record.parent_dir);
    return ret;
}

// 初始化文件系统
void filesys_init() {
    uint8_t channel_no = 0, dev_no = 0, part_idx = 0;

    // sb_buf 用来存储从硬盘上读入的超级块
    struct super_block* sb_buf = (struct super_block*) sys_malloc(SECTOR_SIZE);

    if(sb_buf == NULL) 
        PANIC("alloc memory failed!");
    printk("searching filesystem...\n");

    while(channel_no < channel_cnt) { // 遍历通道
        dev_no = 0;
        while(dev_no < 2) { // 
            if(dev_no == 0) {
                dev_no++;
                continue;
            }
            struct disk* hd = &channels[channel_no].devices[dev_no];
            struct partition* part = hd -> prim_parts;
            while(part_idx < 12) { // 4个主分区 + 8个逻辑分区
                if(part_idx == 4) // 主分区遍历完了，开始切换到逻辑分区
                    part = hd -> logic_parts;
                if(part -> sec_cnt != 0) { // 判断该分区是否存在
                    memset(sb_buf, 0, SECTOR_SIZE);
                    // 读取分区的超级块，根据魔数是否正确来判断是否存在文件系统
                    ide_read(hd, part -> start_lba + 1, sb_buf, 1);
                    // 若该分区已存在文件系统，则不再进行格式化
                    if(sb_buf -> magic == 0x19590318) {
                        printk("%s had filesystem.\n", part -> name);
                    } else {
                        printk("formatting %s's partition %s...\n", hd -> name, part -> name);
                        partition_format(part);
                    }
                }
                part_idx++;
                part++; // 下一个分区
            }
            dev_no++; // 下一个硬盘
        }
        channel_no++; // 下一个通道
    }
    sys_free(sb_buf);

    // 确定默认操作的分区
    char default_part[8] = "sdb1";
    // 挂载分区
    list_traversal(&partition_list, mount_partition, (int) default_part);

    // 将当前分区的根目录打开
    open_root_dir(cur_part);

    // 初始化文件表
    uint32_t fd_idx = 0;
    while(fd_idx < MAX_FILE_OPEN) {
        file_table[fd_idx++].fd_inode = NULL;
    }
}
